﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using System;
using System.Text;
using System.Security.Cryptography;
using System.Reflection;
using Yoozoo.UI.YGUI;
using UnityEngine.UI;

struct StructButton
{
    public string prefabName;
    public string prefabPath;
    public string buttonName;
    public string imageName;
}

class Hierarchy
{
    string _hierarchyPath;

    public string           m_md5;
    public List<Hierarchy>  m_list = new List<Hierarchy>();
    public string           m_comSelfStr;
    public string           m_comTotalStr;
    public string           m_prefabName;
    public string           m_assetPath;
    public string           HierarchyPath
    {
        get
        {
            return _hierarchyPath;
        }
        set
        {
            _hierarchyPath = value;
        }
    }
    public bool             m_discard;      
}

public class AssetAnalysis : Editor
{
    static int s_index = 0;
    
    //[MenuItem("GTATools/Analysis/预制体-按钮相似结构分析", false, 10)]
    public static void ButtonAnalysis()
    {
        Debug.Log($"------ButtonAnalysis-----");
        string prefabPath = "Assets/ResourcesAssets/Prefabs/UI";



        //保存数据结构
        Dictionary<string, Dictionary<string, List<StructButton>>> dictButton = new Dictionary<string, Dictionary<string, List<StructButton>>>();
        //
        Dictionary<string, Dictionary<string, List<StructButton>>> dictImage = new Dictionary<string, Dictionary<string, List<StructButton>>>();
        //
        Dictionary<string, List<StructButton>> dictButtons = new Dictionary<string, List<StructButton>>();

        //AssetDatabase.LoadAssetAtPath
        string[] guids = AssetDatabase.FindAssets("t:Prefab", new string[] { prefabPath });
        string assetPath = "";
        foreach (string guid in guids)
        {
            assetPath = AssetDatabase.GUIDToAssetPath(guid);
            //Debug.Log($"{assetPath}");

            GameObject go = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
               
            //获取所有挂有YButton的节点
            List<YButton> listBtns = new List<YButton>();
            //listBtns.Add(go.GetComponent<YButton>());
            //listBtns.AddRange(go.GetComponentsInChildren<YButton>(true));
            foreach(YButton yButton in go.GetComponentsInChildren<YButton>(true))
            {
                //Debug.Log($"{Path.GetFileName(assetPath)}  {yButton.name} YImage数量:{yButton.GetComponentsInChildren<YImage>(true).Length}");
                List<string> names = new List<string>();
                foreach(YImage yImage in yButton.GetComponentsInChildren<YImage>(true))
                {
                    Dictionary<string, List<StructButton>> dict;
                    if (yImage.sprite == null)
                    {
                        Debug.LogWarning($"{Path.GetFileName(assetPath)} {yImage.name} sprite is null!!!");
                        continue;
                    }
                    if (!dictImage.TryGetValue(yImage.sprite.name, out dict))
                    {
                        dict = new Dictionary<string, List<StructButton>>();
                        dictImage.Add(yImage.sprite.name, dict);
                    }

                    List<StructButton> list;
                    if (!dict.TryGetValue(yButton.name, out list))
                    {
                        list = new List<StructButton>();
                        dict.Add(yButton.name, list);
                    }

                    list.Add(new StructButton {
                        buttonName  = yButton.name,
                        imageName   = yImage.name,
                        prefabName  = Path.GetFileName(assetPath),
                        prefabPath  = assetPath,
                    });


                    //--------------------------------button
                    names.Add(yImage.sprite.name);
                }
                names.Sort();
                string key = string.Join("_", names);
                List<StructButton> sButtons;
                if (!dictButtons.TryGetValue(key, out sButtons))
                {
                    sButtons = new List<StructButton>();
                    dictButtons.Add(key, sButtons);
                }
                sButtons.Add(new StructButton
                {
                    buttonName = yButton.name,
                    prefabName = Path.GetFileName(assetPath),
                    prefabPath = assetPath,
                });


            }

        }




        Resources.UnloadUnusedAssets();

        /*
        foreach (var pair in dictImage)
        {
            if (pair.Value.Count >= 2)
            {
                int count = 0;
                foreach (var pair2 in pair.Value)
                {
                    count += pair2.Value.Count;
                }
                Debug.Log($"------------------------------------{pair.Key}  = {count}-------------------------------------------");

                foreach (var pair2 in pair.Value)
                {
                    //Debug.Log($"--{pair2.Key}  = {pair2.Value.Count}");
                    foreach(var s in pair2.Value)
                    {
                        Debug.Log($"{pair2.Key}   {s.prefabName}   {s.prefabPath}");
                    }
                }
            }
            
        }*/


        foreach (var pair in dictButtons)
        {
            if(pair.Value.Count > 1)
            {
                Debug.Log($"-----------------------相同结构的 Button-----------------------------");
                foreach (var s in pair.Value)
                {
                    Debug.Log($"{s.buttonName}   {s.prefabName}   path:{s.prefabPath}");
                }
            }
            
        }

    }
    //仙心抽公共UI时用的辅助脚本
    [MenuItem("GTATools/UI/Analysis/预制体-相同结构分析", false, 10)]
    //[MenuItem("Tools/PublicComAnalysis", false, -1)]
    public static void ComAnalysis()
    {
        Debug.Log($"------PublicComAnalysis-----");
        s_index = 0;
        string prefabPath = "Assets/ResourcesAssets/Prefabs/UI";

        //保存数据结构
        Dictionary<string, List<Hierarchy>> dictHierarchy = new Dictionary<string, List<Hierarchy>>();
        

        Hierarchy hierarchy = null;
        //AssetDatabase.LoadAssetAtPath
        string[] guids = AssetDatabase.FindAssets("t:Prefab", new string[] { prefabPath });
        string assetPath = "";
        foreach (string guid in guids)
        {
            assetPath = AssetDatabase.GUIDToAssetPath(guid);
            //assetPath = $"{prefabPath}/Commander/CommanderInfoPanel.prefab";
            //Debug.Log($"*-path:{assetPath}");
            GameObject go = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);

            //分析prefab层级列表
            hierarchy = new Hierarchy();
            hierarchy.HierarchyPath = go.transform.name;
            AnalysisHierarchy(go.transform, hierarchy, dictHierarchy, assetPath);

           // break;
        }

        Resources.UnloadUnusedAssets();
        ////////////
        //*
        //同一个prefab中 多个相似的结构 只保留一个
        Dictionary<string, List<Hierarchy>> dictTemp = new Dictionary<string, List<Hierarchy>>();
        foreach(var pair in dictHierarchy)
        {
            HashSet<string> hashTemp = new HashSet<string>();
            List<Hierarchy> listTemp = new List<Hierarchy>();

            if (pair.Value.Count > 1)
            {
                foreach(var item in pair.Value)
                {
                    if (!hashTemp.Contains(item.m_assetPath))
                    {
                        hashTemp.Add(item.m_assetPath);
                        listTemp.Add(item);

                    }
                    
                }
            }

            if (listTemp.Count > 1)
            {
                dictTemp.Add(pair.Key, listTemp);
            }
        }//*/


        //只显示2个以上有相同结构的对象
        List<List<Hierarchy>> listHierarchy = new List<List<Hierarchy>>();
        foreach(var pair in dictTemp)
        {
            if (pair.Value.Count > 2)
            {
                List<Hierarchy> list = new List<Hierarchy>();
                //Debug.Log($"---------------------{pair.Key}-------------------len={pair.Value.Count}");
                foreach (var item in pair.Value)
                {
                    list.Add(item);
                    //Debug.Log($"{item.HierarchyPath}  in  -path:{item.m_assetPath}  com:{item.m_comSelfStr}");
                }
                listHierarchy.Add(list);
            }
            
        }
        //过滤prefab
        foreach(var list in listHierarchy)
        {
            Hierarchy prefabItem = null;
            Hierarchy item = null;
            for (int i = list.Count - 1; i >= 0; i--)
            {
                item = list[i];
                string prefabName = Path.GetFileNameWithoutExtension(item.m_assetPath);
                if (item.HierarchyPath == prefabName)
                {
                    prefabItem = item;
                }
                else
                {
                    //该层级对象是一个prefab并且并不是当前对象所在的prefab
                    string path = item.HierarchyPath.Substring(prefabName.Length + 1);
                    GameObject go = AssetDatabase.LoadAssetAtPath<GameObject>(item.m_assetPath);
                    GameObject goHierarchy = go.transform.Find(path).gameObject;
                    path = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(goHierarchy);
                    if (path != item.m_assetPath)
                    {
                        list.RemoveAt(i);
                        //Debug.Log($"---------path:{path}   prefab:{item.m_assetPath}");
                    }
                }//*/

            }

            //if (prefabItem != null) Debug.Log($"--------{prefabItem.m_assetPath}-len={list.Count}");
            //else Debug.Log($"---------------------------------len={list.Count}");
            if (prefabItem != null)
            {
                for (int i = list.Count - 1; i >= 0; i--)
                {
                    item = list[i];
                    GameObject go = AssetDatabase.LoadAssetAtPath<GameObject>(item.m_assetPath);

                    string prefabName = Path.GetFileNameWithoutExtension(item.m_assetPath);
                    if (item.HierarchyPath != prefabName)
                    {
                        string path = item.HierarchyPath.Substring(prefabName.Length + 1);
                        GameObject goHierarchy = go.transform.Find(path).gameObject;
                        path = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(goHierarchy);
                        if (path == prefabItem.m_assetPath)
                            list.RemoveAt(i);
                        //Debug.Log($"-path:{path}");
                    }
                    
                }
            }

        }


        for(int i = 0; i < listHierarchy.Count; ++i)
        {
            for (int j = i + 1; j < listHierarchy.Count; ++j)
            {
                List<Hierarchy> list1 = listHierarchy[i];
                List<Hierarchy> list2 = listHierarchy[j];
                if (list1.Count > 0 && list2.Count > 0)
                {
                    string name1 = list1[0].HierarchyPath;
                    string name2 = list2[0].HierarchyPath;
                    if (name1.Contains(name2))
                    {
                        list1.Clear();
                        break;
                    }
                    else if (name2.Contains(name1))
                    {
                        list2.Clear();
                    }
                }


            }
        }



        //由多到少排序
        listHierarchy.Sort((a, b) => {
            if (a.Count > b.Count)
                return -1;
            else if (a.Count < b.Count)
                return 1;
            else
                return 0;
        });

        foreach (List<Hierarchy> list in listHierarchy)
        {
            if (list.Count > 1)
            {
                Debug.Log($"----------------------------------------len={list.Count}");
                foreach(Hierarchy item in list)
                {
                    Debug.Log($"{item.HierarchyPath}  in  -path:{item.m_assetPath}  com:{item.m_comSelfStr}");
                }
            }
        }

        Resources.UnloadUnusedAssets();
    }
    
    
    
    
    
    
    //分析prefab层级列表
    private static void AnalysisHierarchy(Transform transform, Hierarchy hierarchy, Dictionary<string, List<Hierarchy>> dictHierarchy, string assetPath, int depth = 0)
    {
        Component[] coms = transform.GetComponents<Component>();
        StringBuilder stringBuilder = new StringBuilder();
        foreach(var com in coms)
        {
            Type t = com?.GetType();
            stringBuilder.Append($"--{0}-{t}");
            if (t == typeof(YImage))
            {
                stringBuilder.Append($":{(com as YImage).sprite},{(com as YImage).material}");
            }
            else if(t == typeof(Image))
            {
                stringBuilder.Append($":{(com as Image).sprite},{(com as Image).material}");
            }
            else if(t == typeof(YTableView))
            {
                stringBuilder.Append($":{++s_index}");
            }
            else if (t == typeof(YGridView))
            {
                stringBuilder.Append($":{++s_index}");
            }
            else if (t == typeof(YList))
            {
                stringBuilder.Append($":{++s_index}");
            }
            else if (t == typeof(Scrollbar))
            {
                stringBuilder.Append($":{++s_index}");
            }
        }
        hierarchy.m_comSelfStr = stringBuilder.ToString();
        hierarchy.m_comTotalStr = hierarchy.m_comSelfStr;
        Transform child = null;
        int childCount = transform.childCount;

        //Debug.Log($"*-hierarchy:{hierarchy.HierarchyPath} Child:{childCount} 组件列表:{ stringBuilder.ToString()} ");
        if (childCount == 0)
        {
            return;
            /*
            YImage yImage = transform.GetComponent<YImage>();
            //过滤 最后一个对象不是图像 或者 没有图像资源
            if (yImage == null || yImage.sprite == null)
            {
                hierarchy.m_discard = true;
                
            }*/
        }
        for (int i = 0; i < childCount; ++i)
        {
            child = transform.GetChild(i);

            Hierarchy _hierarchy = new Hierarchy();
            //该对象的层级路径
            _hierarchy.HierarchyPath = $"{hierarchy.HierarchyPath}/{child.name}";
            //递归查找子对象
            AnalysisHierarchy(child, _hierarchy, dictHierarchy, assetPath, depth + 1);
            
            hierarchy.m_comTotalStr += $"{_hierarchy.m_comTotalStr}";

            if (!hierarchy.m_discard)
            {
                //放入父对象列表
                hierarchy.m_list.Add(_hierarchy);
            }
        }

        if (hierarchy.m_list.Count < 2)
        {
            bool ret = true;
            foreach(Hierarchy item in hierarchy.m_list)
            {
                if (item.m_list.Count > 0)
                {
                    ret = false;
                    break;
                }
            }

            if (ret) return;
        }
        if (hierarchy.m_comTotalStr.IndexOf("Image") == -1)
        {
            return;
        }


        hierarchy.m_md5 = ComputeHash(Encoding.ASCII.GetBytes(hierarchy.m_comTotalStr));
        hierarchy.m_assetPath = assetPath;

        //Debug.Log($"*-hierarchy:{hierarchy.HierarchyPath} 组件列表:{hierarchy.m_comTotalStr}");
        //Debug.Log($"*-hierarchy:{hierarchy.HierarchyPath} 组件列表:{hierarchy.m_md5}");

        List<Hierarchy> list;
        if (!dictHierarchy.TryGetValue(hierarchy.m_md5, out list))
        {
            list = new List<Hierarchy>();
            dictHierarchy.Add(hierarchy.m_md5, list);
        }
        
        list.Add(hierarchy);
    }
    
    static MD5 md5 = null;
    static MD5 MD5
    {
        get
        {
            if (null == md5)
                md5 = MD5.Create();
            return md5;
        }
    }
    static string ComputeHash(byte[] buffer)
    {
        if (null == buffer || buffer.Length < 1)
            return "";

        byte[] hash = MD5.ComputeHash(buffer);
        StringBuilder sb = new StringBuilder();

        foreach (var b in hash)
            sb.Append(b.ToString("x2"));

        return sb.ToString();
    }

}






